package com.xingfly.config;

import com.xingfly.security.jwt.JwtAuthEntryPoint;
import com.xingfly.security.jwt.filter.JwtAuthTokenFilter;
import com.xingfly.security.jwt.service.JwtUserDetailsService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * Created by SuperS on 2016/12/1.
 * prePostEnabled :决定Spring Security的前注解是否可用 [@PreAuthorize,@PostAuthorize,..]
 * secureEnabled : 决定是否Spring Security的保障注解 [@Secured] 是否可用
 *
 * @Secured("ROLE_ADMIN") void updateUser(User user);
 * @Secured，并且只有那些角色/权限的用户才可以调用该方法
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    private final Log logger = LogFactory.getLog(this.getClass());
    @Autowired
    private JwtAuthEntryPoint jwtAuthEntryPoint;
    @Autowired
    private JwtUserDetailsService jwtUserDetailsService;


//    @Autowired
//    private  JwtAccessDeniedHandler jwtAccessDeniedHandler;


    /**
     * Spring Security 配置
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                //错误处理 401
                .exceptionHandling().authenticationEntryPoint(jwtAuthEntryPoint).and()
                //错误处理 403
//                .exceptionHandling().accessDeniedHandler(jwtAccessDeniedHandler).and()
                // 会话管理 创建策略 为 无状态
                .exceptionHandling().accessDeniedPage("/403").and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .authorizeRequests()
                .antMatchers(HttpMethod.GET, "/home", "/", "/img", "/code", "/403", "/404", "/500", "/401").permitAll()
                .antMatchers("/upload").permitAll()
                .antMatchers("/auth/**", "/users/**").permitAll()
                .antMatchers("/mails/**").permitAll()
                .antMatchers(HttpMethod.GET, "/posts/**").permitAll()
                .anyRequest().authenticated();
        //在账号密码验证前添加JwtFilter认证如果Token认证成功通过Token中的信息读取用户信息冰保存到SecurityContext中
        http.addFilterBefore(jwtAuthTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
        http.headers().cacheControl();

    }

    /**
     * 忽略这些链接
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/js/**", "/css/**", "/images/**", "/**/favicon.ico");
    }

    /**
     * 为认证添加自定义的登录认证服务 并且设置密码加密
     */
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(jwtUserDetailsService).passwordEncoder(bCryptPasswordEncoder());
    }

    /**
     * 密码加密
     */
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * Jwt认证过滤器
     */
    @Bean
    public JwtAuthTokenFilter jwtAuthTokenFilterBean() throws Exception {
        return new JwtAuthTokenFilter();
    }


}
